﻿// -----------------------------------------------------------------------
// <copyright file="FilterMaskCalc.cs" company="FCIS">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace IP_Package.Operations.MATLAP_operations
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class FilterMaskCalc
    {
        /// <summary>
        /// the value of mask
        /// </summary>
        private double[,] h;

        /// <summary>
        /// distance between each point and center
        /// </summary>
        private double[,] distanceToCenter1;

        /// <summary>
        /// distance between each point and center in noise
        /// </summary>
        private double[,] distanceToCenter2;

        /// <summary>
        /// value of d0
        /// </summary>
        private double distanceToCut;

        /// <summary>
        /// order of filter
        /// </summary>
        private double filterOrder;

        /// <summary>
        /// Calcs the filter mask to image.
        /// </summary>
        /// <param name="typeOfOperation">The type of operation.</param>
        /// <param name="typeOfMask">The type of mask.</param>
        /// <param name="width">The width.</param>
        /// <param name="heigth">The heigth.</param>
        /// <param name="d0">The d0.</param>
        /// <param name="filterOrder">The order of filter.</param>
        /// <returns>
        /// filter value
        /// </returns>
        public double[,] CalcFilterMaskToImage(string typeOfOperation, string typeOfMask, int width, int heigth, double d0, double filterOrder)
        {
            this.distanceToCut = d0;
            this.filterOrder = filterOrder;
            this.h = new double[width, heigth];
            this.distanceToCenter1 = new double[width, heigth];
            for (int i = 0; i < this.distanceToCenter1.GetLength(1); i++)
            {
                for (int j = 0; j < this.distanceToCenter1.GetLength(0); j++) 
                {
                    this.distanceToCenter1[j, i] = Math.Sqrt(Math.Pow(j - (width / 2), 2) + Math.Pow(i - (heigth / 2), 2));
                }
            }

                if (typeOfMask == "Ideal")
                {
                    this.CalcFilterMaskTOImageIdeal(typeOfOperation);
                }
                else if (typeOfMask == "Butterworth")
                {
                    this.CalcFilterMaskTOImageButterWorth(typeOfOperation);
                }
                else if (typeOfMask == "Gaussian")
                {
                    this.CalcFilterMaskTOImageGaussian(typeOfOperation);
                }

            return this.h;
        }
    
        /// <summary>
        /// Calcs the filter mask to image.
        /// </summary>
        /// <param name="typeOfOperation">The type of operation.</param>
        /// <param name="typeOfMask">The type of mask.</param>
        /// <param name="width">The width.</param>
        /// <param name="heigth">The heigth.</param>
        /// <param name="d0">The d0.</param>
        /// <param name="uc">The uc notch center.</param>
        /// <param name="vc">The vc notch center.</param>
        /// <returns>
        /// filter value
        /// </returns>
        public double[,] CalcFilterMaskToImage(string typeOfOperation, string typeOfMask, int width, int heigth, double d0, double uc, double vc)
        {
            this.distanceToCut = d0;
            this.h = new double[width, heigth];
            this.distanceToCenter1 = new double[width, heigth];
            this.distanceToCenter2 = new double[width, heigth];
            for (int i = 0; i < this.distanceToCenter1.GetLength(1); i++)
            {
                for (int j = 0; j < this.distanceToCenter1.GetLength(0); j++)
                {
                    this.distanceToCenter1[j, i] = Math.Sqrt(Math.Pow(j - (width / 2) + uc, 2) + Math.Pow(i - (heigth / 2) + vc, 2));
                    this.distanceToCenter2[j, i] = Math.Sqrt(Math.Pow(j - (width / 2) - uc, 2) + Math.Pow(i - (heigth / 2) - vc, 2));
                }
            }

            if (typeOfMask == "Ideal")
            {
                this.CalcFilterMaskTOImageIdealNoise(typeOfOperation);
            }
            else if (typeOfMask == "Butterworth")
            {
                this.CalcFilterMaskTOImageButterWorthNoise(typeOfOperation);
            }
            else if (typeOfMask == "Gaussian")
            {
                this.CalcFilterMaskTOImageGaussianNoise(typeOfOperation);
            }

            return this.h;
        }

        /// <summary>
        /// Calcs the filter mask TO image gaussian.
        /// </summary>
        /// <param name="typeOfOperation">The type of operation.</param>
        private void CalcFilterMaskTOImageGaussian(string typeOfOperation)
        {
            for (int i = 0; i < this.h.GetLength(1); i++)
            {
                for (int j = 0; j < this.h.GetLength(0); j++)
                {
                    this.h[j, i] = Math.Exp((-Math.Pow(this.distanceToCenter1[j, i], 2) / (2 * Math.Pow(this.distanceToCut, 2))));
                     if (typeOfOperation == "HPF")
                    {
                        this.h[j, i] = 1 - this.h[j, i];
                    }
                }
            }
        }

        /// <summary>
        /// Calcs the filter mask TO image butter worth.
        /// </summary>
        /// <param name="typeOfOperation">The type of operation.</param>
        private void CalcFilterMaskTOImageButterWorth(string typeOfOperation)
        {
            for (int i = 0; i < this.h.GetLength(1); i++)
            {
                for (int j = 0; j < this.h.GetLength(0); j++)
                {
                    this.h[j, i] = 1 / (1 + Math.Pow(this.distanceToCenter1[j, i] / this.distanceToCut, 2 * this.filterOrder));
                    if (typeOfOperation == "HPF")
                    {
                        this.h[j, i] = 1 - this.h[j, i];
                    }
                }
            }
        }

        /// <summary>
        /// Calcs the filter mask TO image ideal.
        /// </summary>
        /// <param name="typeOfOperation">The type of operation.</param>
        private void CalcFilterMaskTOImageIdeal(string typeOfOperation)
        {
            for (int i = 0; i < this.h.GetLength(1); i++)
            {
                for (int j = 0; j < this.h.GetLength(0); j++)
                {
                    if (typeOfOperation != "Band pass" && typeOfOperation != "Band reject")
                    {
                    if (this.distanceToCenter1[j, i] <= this.distanceToCut)
                    {
                        this.h[j, i] = 1;
                    }
                    else
                    {
                        this.h[j, i] = 0;
                    }

                    if (typeOfOperation == "HPF")
                    {
                        this.h[j, i] = 1 - this.h[j, i];
                    }
                }
                    else
                    {
                        if ((this.distanceToCut - (this.filterOrder / 2.0)) < this.distanceToCenter1[j, i] && (this.distanceToCut + (this.filterOrder / 2.0)) >= this.distanceToCenter1[j, i])
                        {
                            this.h[j, i] = 0;
                        }
                        else
                        {
                            this.h[j, i] = 1;
                        }

                        if (typeOfOperation == "Band pass")
                        {
                            this.h[j, i] = 1 - this.h[j, i];
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Calcs the filter mask TO image gaussian.
        /// </summary>
        /// <param name="typeOfOperation">The type of operation.</param>
        private void CalcFilterMaskTOImageGaussianNoise(string typeOfOperation)
        {
            for (int i = 0; i < this.h.GetLength(1); i++)
            {
                for (int j = 0; j < this.h.GetLength(0); j++)
                {
                    this.h[j, i] = Math.Exp((-Math.Pow(this.distanceToCenter1[j, i], 2) / (2 * Math.Pow(this.distanceToCut, 2))));
                    if (typeOfOperation == "HPF")
                    {
                        this.h[j, i] = 1 - this.h[j, i];
                    }
                }
            }
        }

        /// <summary>
        /// Calcs the filter mask TO image butter worth.
        /// </summary>
        /// <param name="typeOfOperation">The type of operation.</param>
        private void CalcFilterMaskTOImageButterWorthNoise(string typeOfOperation)
        {
            for (int i = 0; i < this.h.GetLength(1); i++)
            {
                for (int j = 0; j < this.h.GetLength(0); j++)
                {
                    this.h[j, i] = 1 / (1 + Math.Pow(this.distanceToCenter1[j, i] / this.distanceToCut, 2 * this.filterOrder));
                    if (typeOfOperation == "HPF")
                    {
                        this.h[j, i] = 1 - this.h[j, i];
                    }
                }
            }
        }

        /// <summary>
        /// Calcs the filter mask TO image ideal.
        /// </summary>
        /// <param name="typeOfOperation">The type of operation.</param>
        private void CalcFilterMaskTOImageIdealNoise(string typeOfOperation)
        {
            for (int i = 0; i < this.h.GetLength(1); i++)
            {
                for (int j = 0; j < this.h.GetLength(0); j++)
                {
                        if (this.distanceToCenter1[j, i] <= this.distanceToCut || this.distanceToCenter2[j, i] <= this.distanceToCut)
                        {
                            this.h[j, i] = 0;
                        }
                        else
                        {
                            this.h[j, i] = 1;
                        }

                        if (typeOfOperation == "Notch pass")
                        {
                            this.h[j, i] = 1 - this.h[j, i];
                        }
                }
            }
        }
    }
}
